package services

import (
	"context"
	"errors"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"

	"zwai-app/db"
	"zwai-app/models"
)

// ErrNotAuthor 操作文章需要作者权限
var ErrNotAuthor = errors.New("not article author")

// UpdateArticleVisibility 只有作者本人可更新 visibility
func UpdateArticleVisibility(ctx context.Context, articleID, userID primitive.ObjectID, visibility string) error {
	coll := db.Client.Database(db.DBName).Collection("Article")

	// 先查文章，确认 authorID
	var art models.Article
	if err := coll.FindOne(ctx, bson.M{"_id": articleID}).Decode(&art); err != nil {
		return err
	}
	if art.AuthorID != userID {
		return ErrNotAuthor
	}

	// 更新 visibility 和 updatedAt
	_, err := coll.UpdateOne(ctx,
		bson.M{"_id": articleID},
		bson.M{"$set": bson.M{"visibility": visibility, "updatedAt": time.Now()}},
	)
	return err
}

// CreateArticle 提交文章，状态为 pending，并处理标签统计
func CreateArticle(ctx context.Context, authorID primitive.ObjectID, art *models.Article) (primitive.ObjectID, error) {
	art.Status = "pending"
	art.AuthorID = authorID
	now := time.Now()
	art.CreatedAt = now
	art.UpdatedAt = now

	coll := db.Client.Database(db.DBName).Collection("Article")
	res, err := coll.InsertOne(ctx, art)
	if err != nil {
		return primitive.NilObjectID, err
	}
	aid := res.InsertedID.(primitive.ObjectID)

	// 处理标签：不存在则插入并计数加1
	tagColl := db.Client.Database(db.DBName).Collection("Tag")
	for _, name := range art.Tags {
		if _, err := tagColl.UpdateOne(
			ctx,
			bson.M{"name": name},
			bson.M{"$inc": bson.M{"usageCount": 1}, "$setOnInsert": bson.M{"name": name}},
			options.Update().SetUpsert(true),
		); err != nil {
			return aid, err
		}
	}
	return aid, nil
}

// ApproveArticle 审核通过
func ApproveArticle(ctx context.Context, id primitive.ObjectID) error {
	coll := db.Client.Database(db.DBName).Collection("Article")
	_, err := coll.UpdateOne(
		ctx,
		bson.M{"_id": id},
		bson.M{"$set": bson.M{"status": "approved", "updatedAt": time.Now()}},
	)
	return err
}

// GetArticleDetail 获取文章详情并增加一次阅读计数
func GetArticleDetail(ctx context.Context, id primitive.ObjectID) (*models.Article, error) {
	coll := db.Client.Database(db.DBName).Collection("Article")
	// 增加 views
	_, _ = coll.UpdateOne(ctx, bson.M{"_id": id}, bson.M{"$inc": bson.M{"views": 1}})

	// 查询已通过的文章
	var art models.Article
	if err := coll.FindOne(ctx, bson.M{"_id": id, "status": "approved"}).Decode(&art); err != nil {
		return nil, err
	}
	return &art, nil
}

// LikeArticle 切换点赞状态
func LikeArticle(ctx context.Context, articleID, userID primitive.ObjectID) error {
	likeColl := db.Client.Database(db.DBName).Collection("ArticleLike")
	// 尝试删除已存在的点赞记录
	result, err := likeColl.DeleteOne(ctx, bson.M{"articleId": articleID, "userId": userID})
	if err != nil {
		return err
	}
	if result.DeletedCount > 0 {
		// 取消点赞
		_, _ = db.Client.Database(db.DBName).Collection("Article").UpdateOne(ctx,
			bson.M{"_id": articleID},
			bson.M{"$inc": bson.M{"likes": -1}},
		)
		return nil
	}

	// 新增点赞
	if _, err := likeColl.InsertOne(ctx, bson.M{"articleId": articleID, "userId": userID}); err != nil {
		return err
	}
	_, _ = db.Client.Database(db.DBName).Collection("Article").UpdateOne(ctx,
		bson.M{"_id": articleID},
		bson.M{"$inc": bson.M{"likes": 1}},
	)
	return nil
}

// AddComment 添加评论或回复
func AddComment(ctx context.Context, c *models.Comment) (primitive.ObjectID, error) {
	c.CreatedAt = time.Now()
	coll := db.Client.Database(db.DBName).Collection("Comment")
	res, err := coll.InsertOne(ctx, c)
	if err != nil {
		return primitive.NilObjectID, err
	}
	cid := res.InsertedID.(primitive.ObjectID)
	// 更新文章 comments
	_, _ = db.Client.Database(db.DBName).Collection("Article").UpdateOne(ctx,
		bson.M{"_id": c.ArticleID},
		bson.M{"$push": bson.M{"comments": cid}},
	)
	return cid, nil
}
func RejectArticle(ctx context.Context, id primitive.ObjectID, reason string) error {
	coll := db.Client.Database(db.DBName).Collection("Article")

	// 先确认文章存在
	var art models.Article
	if err := coll.FindOne(ctx, bson.M{"_id": id}).Decode(&art); err != nil {
		return err
	}
	// 更新状态、原因、更新时间
	_, err := coll.UpdateOne(ctx,
		bson.M{"_id": id},
		bson.M{"$set": bson.M{
			"status":          "rejected",
			"rejectionReason": reason,
			"updatedAt":       time.Now(),
		}},
	)
	return err
}
